﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using CredentialsManager.Common;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;
using ServiceModelEx;

namespace CredentialsManager.ViewModels
{
    public class ServiceViewModel : WorkspaceViewModelBase
    {
        #region Private member variables

        private string m_ServiceUriText;
        private string m_ServiceUri;
        private bool m_IsUriValid;
        private RelayCommand m_ViewCommand;
        private RelayCommand m_SelectCommand;
        private BackgroundWorker m_ValidateContractWorker;

        #endregion

        #region Constructor

        public ServiceViewModel()
            : this(Resources.ServiceViewModelDefaultDisplayName)
        { }

        public ServiceViewModel(string displayName)
        {
            this.DisplayName = displayName;
            this.ServiceUriText = ServiceAddressList.CredentialsService;            
            m_ValidateContractWorker = new BackgroundWorker();
            m_ValidateContractWorker.Initialise(m_ValidateContractWorker_DoWork,
                m_ValidateContractWorker_RunWorkerCompleted, null, false);
            View();
        }

        #endregion

        #region Background worker handlers

        private void m_ValidateContractWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Debug.Assert(e.Argument != null);
            string serviceUri = e.Argument.ToString();
            var isValid = true;

#if !DEBUG
            isValid = IsValidServiceContract(serviceUri);
#endif

            e.Result = isValid;
        }

        private void m_ValidateContractWorker_RunWorkerCompleted(object sender, 
            RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }
            else
            {
                this.IsLoading = false;
                this.IsUriValid = (bool)e.Result;

                if (this.IsUriValid)
                {
                    View();
                    this.CredentialsServiceLocation = this.ServiceUri;
                    Mediator.NotifyColleagues<string>(
                        MediatorMessages.RefreshApplicationList, null);
                }
                else
                {
                    Mediator.NotifyColleagues<bool>(MediatorMessages.SelectServiceViewModel, true);
                    string message = Resources.InvalidContractErrorMessage.ToString();
                    message = string.Format(message, this.ServiceUriText);
                    IMessageBoxService messageBox = base.GetService<IMessageBoxService>();
                    messageBox.Show(message, this.DisplayName, MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }            
        }

        #endregion

        #region Public properties

        public string ServiceUriText
        {
            get
            {
                return m_ServiceUriText;
            }
            set
            {
                m_ServiceUriText = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
                ValidateUri();
            }
        }

        public string ServiceUri
        {
            get
            {
                return m_ServiceUri;
            }
            private set
            {
                m_ServiceUri = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public bool IsUriValid
        {
            get
            {
                return m_IsUriValid;
            }
            private set
            {
                m_IsUriValid = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public string CredentialsServiceLocation
        {
            get
            {
                return ServiceAddressList.CredentialsService;
            }
            private set
            {
                ServiceAddressList.CredentialsService = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        #endregion

        #region Public methods

        public void Select()
        {
            if (this.IsLoading)
            {
                throw new InvalidOperationException();
            }

            Debug.Assert(this.IsUriValid);

            this.IsLoading = true;
            m_ValidateContractWorker.RunWorkerAsync(this.ServiceUriText);
        }

        #endregion

        #region Private methods

        private void View()
        {
            if (this.IsLoading)
            {
                throw new InvalidOperationException();
            }

            Debug.Assert(this.IsUriValid);

            if (!this.ServiceUriText.StartsWith(@"http"))
            {
                this.ServiceUriText = string.Concat(@"http://",
                    this.ServiceUriText);

                if (!this.IsUriValid)
                {
                    return;
                }
            }

            this.ServiceUri = ServiceUriText;
        }

        private bool IsValidServiceContract(string address)
        {
            if (address == string.Empty)
            {
                return false;
            }
            if (!MetadataHelper.QueryContract(address, typeof(IApplicationManager)))
            {
                return false;
            }
            if (!MetadataHelper.QueryContract(address, typeof(IMembershipManager)))
            {
                return false;
            }
            if (!MetadataHelper.QueryContract(address, typeof(IPasswordManager)))
            {
                return false;
            }
            if (!MetadataHelper.QueryContract(address, typeof(IRoleManager)))
            {
                return false;
            }
            if (!MetadataHelper.QueryContract(address, typeof(IUserManager)))
            {
                return false;
            }

            return true;
        }

        private void ValidateUri()
        {
            Regex rgxUrl = new Regex("(([a-zA-Z][0-9a-zA-Z+\\-\\.]*:)?/{0,2}[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?(#[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?");

            this.IsUriValid = (rgxUrl.IsMatch(this.ServiceUriText));            
        }

        #endregion

        #region Commands

        public ICommand ViewCommand
        {
            get
            {
                return m_ViewCommand ?? (m_ViewCommand = new RelayCommand(
                    param => this.View()));
            }
        }

        public ICommand SelectCommand
        {
            get
            {
                return m_SelectCommand ?? (m_SelectCommand = new RelayCommand(
                    param => this.Select()));
            }
        }

        #endregion
    }
}
